package com.ant.common.utils;

import com.ant.create.entity.ColumnInformation;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;

import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class CreateCodeUtil {

    private static final List<String> codeTemplateList = new ArrayList<>();

    private static final List<String> fileList = new ArrayList<>();

    /**
     * 初始化
     *
     * @return
     */
    @SneakyThrows
    public static CreateCodeUtil init(String codePackage, String templates) {
        CreateCodeUtil createCodeUtil = new CreateCodeUtil();

        try {
            if (StringUtil.isEmpty(codePackage)) {
                throw new Exception("生成代码所在路径不能为空");
            }

            if (StringUtil.isEmpty(templates)) {
                throw new Exception("生成代码文件不能为空");
            }

            for (String template : templates.split(",")) {
                switch (template) {
                    case "entity":
                        codeTemplateList.add("Entity.java");
                        fileList.add(codePackage + "entity/");
                        break;
                    case "mapper":
                        codeTemplateList.add("Mapper.java");
                        fileList.add(codePackage + "mapper/");
                        break;
                    case "service":
                        codeTemplateList.add("Service.java");
                        fileList.add(codePackage + "service/");
                        break;
                    case "serviceImpl":
                        codeTemplateList.add("ServiceImpl.java");
                        fileList.add(codePackage + "service/impl/");
                        break;
                    case "controller":
                        codeTemplateList.add("Controller.java");
                        fileList.add(codePackage + "controller/");
                        break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return createCodeUtil;
    }

    /**
     * 生成代码主方法
     *
     * @param tableName
     * @param tableDesc
     * @param columnInformationList
     */
    @SneakyThrows
    public void createCode(String tableName, String tableDesc, List<ColumnInformation> columnInformationList, Map<String, String> packageMap) {
        if (codeTemplateList.size() == 0 || fileList.size() == 0) {
            throw new Exception("生成文件不能为空，请重新配置");
        }

        VelocityContext context = new VelocityContext();
        Map<String, String> entity = getEntity(tableName, columnInformationList);
        String domainUpper = entity.get("domainUpper");
        //小驼峰
        context.put("domain", entity.get("domain"));
        //大驼峰
        context.put("domainUpper", entity.get("domainUpper"));
        //实体类
        context.put("domainParams", entity.get("domainParams"));
        //表名称
        context.put("tableName", tableName);
        //表描述
        context.put("domainDesc", tableDesc);
        //创建时间
        context.put("createTime", DateUtils.getNowStr());
        //主键，用于controller判断条件
        context.put("primaryKey", entity.get("primaryKey"));
        //主键判断，用于controller判断值
        context.put("judgePrimaryKey", entity.get("judgePrimaryKey"));

        context.put("allPackage", packageMap.get("allPackage"));
        context.put("servicePackage", packageMap.get("servicePackage"));
        context.put("daoPackage", packageMap.get("daoPackage"));
        context.put("domainPackage", packageMap.get("domainPackage"));
        context.put("controllerPackage", packageMap.get("controllerPackage"));

        for (int i = 0; i < fileList.size(); i++) {
            Template template = Velocity.getTemplate("/template/" + codeTemplateList.get(i), "UTF-8");

            File file = null;
            if ("Entity.java".equals(codeTemplateList.get(i))) {
                //如果是实体类，不需要后缀，直接跟着 .java，
                //例如：User实体类，不能拼成 UserDomain.java，而是 User.java，所以截取6位，把 Domain 去掉
                file = new File(fileList.get(i) + domainUpper + codeTemplateList.get(i).substring(6));
            } else {
                //路径举例：src/main/java/com/canteen/create/service/UserService.java
                file = new File(fileList.get(i) + domainUpper + codeTemplateList.get(i));
            }

            if (file.exists()) {
                continue;
            }

            File parentFile = file.getParentFile();
            if (!parentFile.exists()) {
                //如果没有上级，则创建
                parentFile.mkdirs();
            }

            log.info(file.getAbsolutePath());
            FileWriter fileWriter = new FileWriter(file);
            template.merge(context, fileWriter);
            fileWriter.close();
        }
    }

    /**
     * 得到模板类里要替换的key-value
     *
     * @param tableName
     * @param informationSchemas
     * @return
     */
    private Map<String, String> getEntity(String tableName, List<ColumnInformation> informationSchemas) {
        Map<String, String> map = new HashMap<>();

        //先生成实体类
        StringBuilder domainParams = new StringBuilder();
        for (ColumnInformation informationSchema : informationSchemas) {
            //字段名称
            String columnName = informationSchema.getColumnName();
            //小驼峰字段名称
            String camelColumnName = StringUtil.underlineToCamel(columnName);
            //字段类型
            String dataType = StringUtil.formatSqlParam(informationSchema.getDataType());
            //字段说明
            String columnComment = informationSchema.getColumnComment();
            //注释
            domainParams.append("    /**\n");
            domainParams.append("     * ").append(columnComment).append("\n");
            domainParams.append("     */").append("\n");
            //PRI是主键
            if (informationSchema.getColumnKey().equals("PRI")) {
                if (informationSchema.getExtra().equals("auto_increment")) {
                    //如果是自增就是 auto
                    domainParams.append("     @TableId(value = \"").append(columnName).append("\", type = IdType.AUTO)").append("\n");
                } else {
                    domainParams.append("     @TableId(value = \"").append(columnName).append("\", type = IdType.NONE)").append("\n");
                }
                //将主键的大驼峰记下来
                map.put("primaryKey", StringUtil.camelToUpper(StringUtil.underlineToCamel(columnName)));

                if (informationSchema.getDataType().equals("varchar")) {
                    map.put("judgePrimaryKey", ".equals(\"\")");
                } else {
                    map.put("judgePrimaryKey", "<=0");
                }
            } else {
                domainParams.append("     @TableField(value = \"").append(columnName).append("\")").append("\n");
            }
            //字段
            domainParams.append("     private ").append(dataType).append(" ").append(camelColumnName).append(";\n\n");
        }

        String domainName = tableName.replace("tb_", "");
        String domain = StringUtil.underlineToCamel(domainName);
        //实体类，通过表名称得到，小驼峰
        map.put("domain", domain);
        //转化为大驼峰
        map.put("domainUpper", StringUtil.camelToUpper(domain));
        //实体类的参数内容
        map.put("domainParams", domainParams.toString());
        return map;
    }


}
